package com.example.websocket.sort;

import java.util.Arrays;

/**
 * 堆排序，将数组看作二叉树进行排序，先将数据调整为大顶堆即最大堆，再进行排序，堆顶与堆底依次交换并进行堆调整。
 * -----------------------------------------------------------------------------------------
 * 堆排序是一种选择排序，整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。
 * 其中构建初始堆经推导复杂度为O(n)，在交换并重建堆的过程中，需交换n-1次，而重建堆的过程中，根据完全二叉树的性质，
 * [log2(n-1),log2(n-2)...1]逐步递减，近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。
 */
public class HeapSort {

    /**
     * 调整大顶堆（仅是调整过程，建立在大顶堆已构建的基础上）
     * @param nums
     * @param i
     * @param length
     */
    public void adjustHeap(int[] nums, int i, int length) {
        int temp = nums[i];
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
            if (k + 1 < length && nums[k] < nums[k + 1]) {
                k++;
            }
            if (nums[k] > temp) {
                nums[i] = nums[k];
                i = k;
            } else {
                break;
            }
        }
        nums[i] = temp;
    }

    public void heap(int[] nums) {
        //1.构建大顶堆
        for (int i = nums.length / 2 - 1; i >= 0; i--) {
            adjustHeap(nums, i, nums.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for (int j = nums.length - 1; j > 0; j--) {
            swap(nums, 0, j);
            adjustHeap(nums, 0, j);
        }
    }

    /**
     * 交换元素
     * @param arr
     * @param a
     * @param b
     */
    public static void swap(int []arr, int a ,int b){
        int temp=arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

    public static void main(String[] args) {
        int []arr = {9,8,7,6,5,4,3,2,1};
        HeapSort h = new HeapSort();
        long startTime = System.nanoTime();;
        h.heap(arr);
        long endTime = System.nanoTime();;
        System.out.println("程序运行时间：" + (endTime - startTime) + "ms");
        System.out.println(Arrays.toString(arr));
    }
}
